#pragma once
#ifdef LIT_OGRE_SUPPORT

#ifndef __PHYSICS__BODY__INCLUDED__HH__
#define __PHYSICS__BODY__INCLUDED__HH__

#include <Newton.h>
#include <Ogre.h>
#include "LitPhysicsPrereqs.h"
#include <LitEntity.h>
#include <boost\function.hpp>

namespace Lit
{
	namespace Physics
	{
		class LIT_API Body
		{
		public:
			typedef boost::function<void( void * userData, int vert_cnt, const float * faceArray, int fid )> PolygonIteratorType;
			static PolygonIteratorType mPolygonIterator;
			
		protected:
			static void _newtonPerPolyDummy( void * userData, int vert_cnt, const float * faceArray, int fid );
			static void _newtonPerPoly( void * userData, int vert_cnt, const float * faceArray, int fid );
		public:

			Body( World * world, Lit::Real mass = 0.0f, Lit::Entity * ent = NULL, NewtonBody * body = NULL, CollisionShape* shape = NULL );
			~Body();
			
			void setFreeState( bool state );
			void setAutoSleep( bool sleep );

			bool isAutoSleeping() const;
			bool isFrozen() const;

			void setMaterialName( const String &name );
			void setMaterial( Ogre::MaterialPtr mat );
			String getMaterialName();
			Ogre::MaterialPtr getMaterial();

			// for each collision face
			// user data is this
			void forEachPolygon( PolygonIteratorType itor, const Matrix& matrix = Matrix() );

			// Translation/Orientation Matrix
			// In Ogre Coordinates
			void		setMatrix( Matrix mat );
			// Translation/Orientation Matrix
			// In Ogre Coordinates
			Matrix		getMatrix( ) const;
		
			// Mass/Inertia Matrix
			void		setMassMatrix( const MassMatrix& matrix );
			// Mass/Inertia Matrix
			MassMatrix	getMassMatrix() const;
		
			// Sets Mass/Inertia Matrix
			Lit::Vec3		getInertia() const;
			InertialMatrix	getInertialMatrix() const;
			void			setInertia( const InertialMatrix& matrix );
		
			ForceList& getExternalForces();
			const ForceList& getExternalForces() const;

			void resetExternalForces( );
			void setExternalForces( const Physics::Force& extF );
			void addExternalForce( const Physics::Force& f );
			_CollisionPtr getCollision() const;
			// Center Of Mass
			void		setCenterOfMass( const Lit::Vec3& com );
			Lit::Vec3	getCenterOfMass() const;
		
			Lit::Vec3	getPosition() const;
			Lit::Quat	getOrientation() const;

			void		setPosition( const Lit::Vec3& p );
			void		setOrientation(const Lit::Quat& o);
		
			Lit::AABB	getBoundingBox() const;
		

			Lit::Entity*				getEntity();
			const Lit::Entity*			getEntity() const;

			NewtonBody*					getBody();
			const NewtonBody*			getBody() const;

			const CollisionShape*		getShape() const;
			CollisionShape*				getShape();
			void						setShape( CollisionShape * shape );

			Lit::Real					getMass() const;
			String					getName() const;

			void						setInitialState( const BodyState& state );
			BodyState*					getInitialState() const;

			void						defineInitialState();
			void						restoreInitialState();

			void						restoreState( BodyState &state );
			BodyState					captureState() const;

			void						_setWorld( World * w );
			const World*				getWorld() const;
			World *						getWorld();
			bool						isStatic() const;
			void						_setStatic( bool state );

		protected:
			void						_releaseCollision( bool destroy_geometry = true );

			bool							mStatic;
			World*							mWorld;
			CollisionShape			*		mShape;
			Lit::Entity*					mEntity;
			NewtonBody*						mBody;
			Lit::Real						mMass;
			BodyState			*			mInitialState;
			ForceList						mForces;

		};
	
		class LIT_API BodyIterator
		{
			Body *			pCur;
			World*			pWorld;
		public:
			BodyIterator( World * world );
			BodyIterator( const BodyIterator& rk );
			~BodyIterator();
		
			BodyIterator& operator=( const BodyIterator& rk );

			World* getWorld() const;	
			Body * getCurrent();
			Body * getNext();
		};
		class LIT_API BodyConstIterator
		{
			const Body *			pCur;
			const World*			pWorld;
		public:
			BodyConstIterator( const World * world );
			BodyConstIterator( const BodyConstIterator& rk );
			~BodyConstIterator();
		
			BodyConstIterator& operator=( const BodyConstIterator& rk );

			const World* getWorld() const;		
			const Body * getCurrent();
			const Body * getNext();
		};

		class LIT_API BodySerializer
		{
		public:
			BodySerializer( );
			~BodySerializer( );
			
			void exportFile( Body * body, const String &filename );
			Body* importFile( World * world, const String &filename );
		};
		typedef Lit::RefPtr<Body> BodyPtr;
	};
};
#endif

#endif